/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.opensudoku.root.concrete;

import java.util.Vector;

import org.opensudoku.root.SudokuConstants;
import org.opensudoku.root.exceptions.InvalidBoxEntryException;
import org.opensudoku.root.exceptions.InvalidDimensionException;
import org.opensudoku.root.exceptions.UnIntializedParameterException;
import org.opensudoku.root.fon.voidClass;
import org.opensudoku.root.vsb.VirtualSudokuBoard;

/**
 *
 * @author sony
 */
//Solving the puzzle using LCF Backtracking...
/**
 * Concrete Step class...
 * @author sony
 */
public class ConcreteAnalyser {
    private Vector<?> CVV;
    private int[] indexVector;
    private int[] lenVector;
    private VirtualSudokuBoard vsb;

    private int CurrentVoid;
    private boolean StopFlag;
    private Vector<VirtualSudokuBoard> solutionVector;

    public ConcreteAnalyser()
    {
        this.CVV=null;
        this.indexVector=null;
        this.lenVector=null;
        this.vsb=null;
        this.CurrentVoid=0;
        this.StopFlag=false;
    }

    /**
     * Constructor
     * @param cvv
     * @param v
     * @throws InvalidDimensionException
     * @throws InvalidBoxEntryException
     */
    public ConcreteAnalyser(Vector<?> cvv,VirtualSudokuBoard v) throws InvalidDimensionException, InvalidBoxEntryException
    {
        int i=0;
        this.CVV=(Vector<?>) cvv.clone();
        this.vsb=ConcreteSupportClass.ReturnVsbObject(v);
        this.indexVector=new int[this.CVV.size()];
        this.lenVector=new int[this.CVV.size()];
        for(Object ob:this.CVV)
            this.lenVector[i++]=((voidClass)ob).getPossibilityCount();
        this.CurrentVoid=0;
        this.StopFlag=false;
    }
    /**
     *
     * @return Returns the solved board states after concrete analysis
     * @throws UnIntializedParameterException
     * @throws InvalidDimensionException
     * @throws InvalidBoxEntryException
     */
    public Vector<VirtualSudokuBoard> doConcreteAnalysis() throws UnIntializedParameterException, InvalidDimensionException, InvalidBoxEntryException
    {
        if(this.CVV==null)
            throw new UnIntializedParameterException("ConcreteAnalyser.CVV");
        this.solutionVector=new Vector<VirtualSudokuBoard>();
        while(!this.StopFlag)
        {
            voidClass ob=(voidClass)this.CVV.get(CurrentVoid);
            if(ConcreteSupportClass.CheckForPlacement(this.vsb, ob.getRow(), ob.getCol(), ob.getNthPoss(this.indexVector[this.CurrentVoid])))
            {
                this.setVoid();

                //Continue if OK...
                this.Continue();
            }
            else
            {
                //Else BackTrack
                this.LCFBackTrak();
            }
        }
        return this.solutionVector;
    }

    private void setVoid() throws InvalidDimensionException, InvalidBoxEntryException
    {
        voidClass ob=(voidClass)this.CVV.get(CurrentVoid);
        
        //Updating the CurrentVoid with a allowable possible value
        this.vsb.update(ob.getRow(), ob.getCol(), ob.getNthPoss(this.indexVector[this.CurrentVoid]));
    }

    //Lowest Cardinality First BackTracking
    /**
     * Modified Backtracking function
     * @throws InvalidDimensionException
     * @throws InvalidBoxEntryException
     */
    private final void LCFBackTrak() throws InvalidDimensionException, InvalidBoxEntryException
    {
        boolean continueFlag=false;
        do
        {
            //Unsetting the CurrentVoid Place...
            this.unsetVoid();

            //Updating the Inter-Related List...
            continueFlag=((this.indexVector[this.CurrentVoid]=((this.indexVector[this.CurrentVoid]+1)%this.lenVector[this.CurrentVoid])))==0;
            
            //if(continueFlag) ----> This is depricated legacy method...
            //    this.CurrentVoid--;
            //Dont change the below order of testing conditons, i.e. "(continueFlag && --this.CurrentVoid>=0)"
            //Because --this.CurrentVoid>=0 is to be done if continueflag is true,so we're using '&&' instead of '&'
            //So we can reduce one comparison for each call of LCFBackTrack() by depricating legacy method.
        }while( continueFlag && (--this.CurrentVoid) >= 0);

        this.StopFlag = (this.CurrentVoid == -1);
    }

    private void unsetVoid() throws InvalidDimensionException, InvalidBoxEntryException {
        voidClass ob=(voidClass)this.CVV.get(CurrentVoid);

        //Updating the CurrentVoid with '0'
        this.vsb.update(ob.getRow(), ob.getCol(), 0);
    }

    private final void Continue() throws InvalidDimensionException, InvalidBoxEntryException
    {
        //Checking whether solution state is obtained or not...
        if(this.CurrentVoid==(this.CVV.size()-1))
        {
            //Checking whether current no of solutions exceeds the maximum solution limit...
            if(this.solutionVector.size()<SudokuConstants.getSudokuMaxSolutionLimit())
            {
                //Adding the solution to solution vector as VSB object...
                this.solutionVector.addElement(this.ReturnAsBoard(this.vsb.ReturnBoard()));
                //Backtracking to get next possible solutions...
                this.LCFBackTrak();
            }
            else
                //Setting stopflag after current no of solutions exceeds the maximum solution limit...
                this.StopFlag=true;
        }
        else
            //Moving down in the State Space Tree if current state is not representing the solution state...
            this.CurrentVoid++;
    }
    private VirtualSudokuBoard ReturnAsBoard(int[][] v) throws InvalidDimensionException, InvalidBoxEntryException
    {
        //Creating new 2D Array and also returning the corresponding VSB
        int[][] temp=new int[9][9];
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
                temp[i-1][j-1]=v[i-1][j-1];
        return new VirtualSudokuBoard(temp);
    }
}
